package com.yincheng.oes.business.service.impl;

import com.yincheng.oes.business.consist.ResultCodeEnum;
import com.yincheng.oes.business.dao.DailyClockDao;
import com.yincheng.oes.business.model.dto.ExerciseCompletionDTO;
import com.yincheng.oes.business.model.dto.StudentDailyClockDTO;
import com.yincheng.oes.business.model.dto.TPStudentDailyTaskDTO;
import com.yincheng.oes.business.model.entity.ExerciseCompletionDO;
import com.yincheng.oes.business.model.entity.StudentDailyClockDO;
import com.yincheng.oes.business.model.query.AuditDailyClockListReq;
import com.yincheng.oes.business.model.query.MyDailyClockListReq;
import com.yincheng.oes.business.model.query.TodayClockCheckReq;
import com.yincheng.oes.business.model.result.AuditDailyClockListResult;
import com.yincheng.oes.business.model.result.BusinessResult;
import com.yincheng.oes.business.model.result.MyDailyClockListResult;
import com.yincheng.oes.business.service.DailyClockService;
import com.yincheng.oes.business.service.StudentDailyTaskQueryApi;
import com.yincheng.oes.business.util.DigitalUtils;
import com.yincheng.oes.business.util.Page;
import com.yincheng.oes.business.util.SpringContextUtils;
import com.yincheng.oes.business.util.StringUtil;
import com.yincheng.oes.business.util.book.dao.BookDao;
import com.yincheng.oes.business.util.book.entity.BookDO;
import com.yincheng.oes.sso.entity.User;
import com.yincheng.oes.sso.mapper.UserMapper;
import com.yincheng.oes.sso.util.UserUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * @author yangsiyong
 * @version 1.0
 * @description: 每日打卡服务类
 * @date 2022/2/13 6:47 PM
 */
@Service
public class DailyClockServiceImpl implements DailyClockService, InitializingBean {
    /**
     * 日志
     */
    private static final Logger LOGGER = LogManager.getLogger(DailyClockServiceImpl.class);
    /**
     * 线程池，用来处理第三方数据
     */
    private final static ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(10);

    private final static SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");

    @Autowired
    private DailyClockDao dailyClockDao;

    @Autowired
    private BookDao bookDao;

    @Autowired
    private StudentDailyTaskQueryApi studentDailyTaskQueryApi;

    private Map<Integer, BookDO> booksCache;

    public BusinessResult checkDailyClock() {
        TodayClockCheckReq req = new TodayClockCheckReq();
        String userId = UserUtils.getUser().getUserId();
        Date startDate = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
        req.setUserId(userId);
        req.setPunchTime(startDate);
        int total = dailyClockDao.countTodayClock(req);
        if (total > 0) {
            return new BusinessResult(ResultCodeEnum.DUPLICATE_REQ);
        }
        return new BusinessResult(ResultCodeEnum.SUCCESS);
    }

    public Pair<Integer, List<MyDailyClockListResult>> getMyDailyClockList(MyDailyClockListReq param) {
        List<MyDailyClockListResult> results = new ArrayList<>();
        if (Objects.isNull(param)) {
            return Pair.of(0, results);
        }
        Page page = param.getPage();
        param.setUserId(UserUtils.getUser().getUserId());
        int total = dailyClockDao.countMyDailyClockList(param);
        page.setTotal(total);
        List<StudentDailyClockDO> studentDailyClockDOS = dailyClockDao.selectMyDailyClockList(param);
        if (CollectionUtils.isEmpty(studentDailyClockDOS)) {
            return Pair.of(0, results);
        }
        results = studentDailyClockDOS.stream().map(studentDailyClockDO -> {
            MyDailyClockListResult result = new MyDailyClockListResult();
            result.setDailyClockId(studentDailyClockDO.getStudentDailyClockId());
            result.setDailyTaskCorrectRate(studentDailyClockDO.getDailyTaskCorrectRate());
            result.setEnglishClockUrl(studentDailyClockDO.getEnglishClockUrl());
            result.setPunchTime(studentDailyClockDO.getPunchTime());
            result.setUserId(studentDailyClockDO.getUserId());
            result.setLiveBroadcastState(studentDailyClockDO.getLiveBroadcastState());
            result.setRecordedBroadcastCompletion(studentDailyClockDO.getRecordedBroadcastCompletion());
            return result;
        }).collect(Collectors.toList());
        return Pair.of(total, results);
    }

    public Pair<Integer, List<AuditDailyClockListResult>> getAuditDailyClockList(AuditDailyClockListReq param) {
        LOGGER.debug("start get auditDailyClockList, param is {}", param);
        List<AuditDailyClockListResult> results = new ArrayList<>();
        if (Objects.isNull(param)) {
            return Pair.of(0, results);
        }
        Map<String, User> userMap = new HashMap<>();
        String userId = UserUtils.getUser().getUserId();
        List<User> users = dailyClockDao.selectUsersByAssistantId(userId);
        LOGGER.debug("after selectUsersByAssistantId, users size is {}", CollectionUtils.size(users));
        if (CollectionUtils.isEmpty(users)) {
            return Pair.of(0, results);
        }
        users.forEach(user -> {
            userMap.put(user.getUserId(), user);
        });
        if (StringUtils.isEmpty(param.getUserId())) {
            List<String> userIds = users.stream().map(User::getUserId).collect(Collectors.toList());
            param.setUserIds(userIds);
        } else {
            param.addUserId(param.getUserId());
        }
        int count = dailyClockDao.countAuditDailyClockList(param);
        LOGGER.debug("after countAuditDailyClockList, count is {}", count);
        Page page = param.getPage();
        page.setTotal(count);
        List<StudentDailyClockDO> studentDailyClockDOS = dailyClockDao.selectAuditDailyClockList(param);
        LOGGER.debug("after countAuditDailyClockList, studentDailyClockDOS size is {}", CollectionUtils.size(studentDailyClockDOS));
        if (CollectionUtils.isEmpty(studentDailyClockDOS)) {
            return Pair.of(0, results);
        }
        results = studentDailyClockDOS.stream().map(studentDailyClockDO -> {
            AuditDailyClockListResult result = new AuditDailyClockListResult();
            result.setDailyClockId(studentDailyClockDO.getStudentDailyClockId());
            result.setEnglishClockUrl(studentDailyClockDO.getEnglishClockUrl());
            result.setPunchTime(studentDailyClockDO.getPunchTime());
            result.setUserId(studentDailyClockDO.getUserId());
            result.setDailyTaskCorrectRate(studentDailyClockDO.getDailyTaskCorrectRate());
            result.setLiveBroadcastState(studentDailyClockDO.getLiveBroadcastState());
            result.setRecordedBroadcastCompletion(studentDailyClockDO.getRecordedBroadcastCompletion());
            result.setEnglishStudyState(studentDailyClockDO.getEnglishStudyState());
            String userName = Optional.ofNullable(userMap.get(studentDailyClockDO.getUserId())).map(User::getUserName).orElse("");
            result.setUserName(userName);
            return result;
        }).collect(Collectors.toList());
        LOGGER.debug("return auditDailyClockList, size is {}, userId is {}", CollectionUtils.size(results), userId);
        return Pair.of(count, results);
    }


    @Transactional
    @Override
    public BusinessResult doDailyClock(StudentDailyClockDTO studentDailyClockDTO) {
        // 0.校验打卡信息
        BusinessResult result = doCheckDailyClock(studentDailyClockDTO);
        if (result.getCode() != 0) {
            return result;
        }
        // 1.构建并分析打卡信息
        StudentDailyClockDO studentDailyClockDO = buildStudentDailyClockDO(studentDailyClockDTO);

        // 2.保存打卡信息 先删除再保存，保证幂等
        dailyClockDao.deleteDailyClock(studentDailyClockDTO.getStudentDailyClockId());
        dailyClockDao.saveDailyClock(studentDailyClockDO);

        dailyClockDao.batchDeleteExerciseCompletions(studentDailyClockDTO.getStudentDailyClockId());
        if (CollectionUtils.isNotEmpty(studentDailyClockDO.getExerciseCompletions())) {
            dailyClockDao.batchSaveExerciseCompletion(studentDailyClockDO.getExerciseCompletions());
        }

        // todo maybe mysql deadlock or primary key not found, need more test
        saveStudentTPDailyTask(studentDailyClockDO);
        // todo 3.异步生成雷达图
        return result;
    }

    @Override
    public BusinessResult doAuditDailyClock(StudentDailyClockDTO studentDailyClockDTO) {
        // 0.校验打卡信息
        BusinessResult result = doCheckDailyClock(studentDailyClockDTO);
        if (result.getCode() != 0) {
            return result;
        }
        // 1.构建并分析打卡信息
        StudentDailyClockDO studentDailyClockDO = buildAuditDailyTask(studentDailyClockDTO);
        // 2.更新每日打卡
        dailyClockDao.updateDailyTask(studentDailyClockDO);

        // 3.异步更新第三方app 学员每日信息
        saveStudentTPDailyTask(studentDailyClockDO);
        return result;
    }

    public StudentDailyClockDO buildAuditDailyTask(StudentDailyClockDTO studentDailyClockDTO) {
        String studentDailyClockId = studentDailyClockDTO.getStudentDailyClockId();
        StudentDailyClockDO studentDailyClockDO = dailyClockDao.selectAuditDailyClock(studentDailyClockId);
        studentDailyClockDO.setStudentDailyClockId(studentDailyClockId);
        studentDailyClockDO.setEnglishStudyState(studentDailyClockDTO.getEnglishStudyState());
        return studentDailyClockDO;
    }

    /**
     * 保存学员每日任务信息 from third app
     *
     * @param dailyTask 学员每日任务相关信息
     * @return BusinessResult
     */
    public BusinessResult saveStudentTPDailyTask(StudentDailyClockDO dailyTask) {
        if (Objects.isNull(dailyTask) || StringUtils.isEmpty(dailyTask.getUserId())
                || StringUtils.isEmpty(dailyTask.getStudentDailyClockId())) {
            LOGGER.error("when save student tp daily task, studentDaily task or userId or dailyClockId is empty");
            return new BusinessResult(ResultCodeEnum.NO_QUERY_PARAM);
        }
        EXECUTOR_SERVICE.execute(() -> {
            UserMapper userMapper = SpringContextUtils.getBean(UserMapper.class);
            if (userMapper == null) {
                LOGGER.error("get userMapper error");
                return;
            }
            String userId = dailyTask.getUserId();
            User user = userMapper.selectByUserId(userId);
            if (Objects.isNull(user)) {
                LOGGER.error("get user error, userId is {}", userId);
                return;
            }
            if (StringUtils.isEmpty(user.getUserAccount())) {
                LOGGER.error("get user account error, userId is {}", userId);
                return;
            }
            StudentDailyTaskQueryApi tpQueryService = SpringContextUtils.getBean(StudentDailyTaskQueryApi.class);
            Date punchTime = dailyTask.getPunchTime() == null ? new Date() : dailyTask.getPunchTime();
            String userAccount = user.getUserAccount();

            TPStudentDailyTaskDTO dailyTaskDTO = tpQueryService.queryStudentDailyTaskByPunchDate(userAccount, punchTime);
            if (Objects.isNull(dailyTaskDTO)) {
                LOGGER.error("get tp daily task error, account is {}", user.getUserAccount());
                return;
            }

            updateDailyTask(dailyTask.getStudentDailyClockId(), dailyTaskDTO);
        });
        return new BusinessResult(ResultCodeEnum.SUCCESS);
    }

    public int updateDailyTask(String dailyClockId, TPStudentDailyTaskDTO dailyTaskDTO) {
        if (StringUtils.isEmpty(dailyClockId)) {
            LOGGER.error("when update dailyTask, dailyClockId is null");
            return 0;
        }
        if (Objects.isNull(dailyTaskDTO)) {
            LOGGER.error("when update dailyTask, dailyTaskDTO is null");
            return 0;
        }
        DailyClockDao dailyClockDao = SpringContextUtils.getBean(DailyClockDao.class);
        if (dailyClockDao == null) {
            LOGGER.error("get dailyClockDao error");
            return 0;
        }
        StudentDailyClockDO studentDailyClockDO = new StudentDailyClockDO();
        studentDailyClockDO.setStudentDailyClockId(dailyClockId);
        studentDailyClockDO.setDailyTaskCorrectNum(dailyTaskDTO.getDailyTaskCorrectNum());
        studentDailyClockDO.setDailyTaskTotalNum(dailyTaskDTO.getDailyTaskTotalNum());
        studentDailyClockDO.setRecordedBroadcastRealNum(dailyTaskDTO.getRecordedBroadcastCompletedCount());
        studentDailyClockDO.setRecordedBroadcastTotalNum(dailyTaskDTO.getRecordedBroadcastTotalCount());
        studentDailyClockDO.setLiveBroadcastState(StringUtil.valueOf(dailyTaskDTO.getLiveBroadcastState()));
        String dailyTaskCorrectRate = DigitalUtils.getPercentage(dailyTaskDTO.getDailyTaskCorrectNum(),
                dailyTaskDTO.getDailyTaskTotalNum(), 2);
        studentDailyClockDO.setDailyTaskCorrectRate(dailyTaskCorrectRate + "%");
        String recordedBroadcastCompletion = DigitalUtils.getPercentage(dailyTaskDTO.getRecordedBroadcastCompletedCount(),
                dailyTaskDTO.getRecordedBroadcastTotalCount(), 2);
        studentDailyClockDO.setRecordedBroadcastCompletion(recordedBroadcastCompletion + "%");
        return dailyClockDao.updateDailyTask(studentDailyClockDO);
    }

    public int updateDailyTask(TPStudentDailyTaskDTO dailyTaskDTO) {
        DailyClockDao dailyClockDao = SpringContextUtils.getBean(DailyClockDao.class);
        if (dailyClockDao == null) {
            LOGGER.error("get dailyClockDao error");
            return 0;
        }
        if (Objects.isNull(dailyTaskDTO) || StringUtils.isEmpty(dailyTaskDTO.getUserId()) ||
                (dailyTaskDTO.getTaskDateIntValue() == null)) {
            LOGGER.error("dailyTask or param is null");
            return 0;
        }
        TodayClockCheckReq req = new TodayClockCheckReq();
        req.setUserId(dailyTaskDTO.getUserId());
        req.setPunchDate(dailyTaskDTO.getTaskDateIntValue());
        StudentDailyClockDO dailyClockDO = dailyClockDao.selectByUserId(req);
        if (Objects.isNull(dailyClockDO)) {
            LOGGER.warn("query dailyClock is null, param is {}", req);
            return 0;
        }
        return updateDailyTask(dailyClockDO.getStudentDailyClockId(), dailyTaskDTO);
    }

    private BusinessResult doCheckDailyClock(StudentDailyClockDTO studentDailyClockDTO) {
        BusinessResult result = new BusinessResult(ResultCodeEnum.SUCCESS);
        if (Objects.isNull(studentDailyClockDTO) || StringUtils.isEmpty(studentDailyClockDTO.getStudentDailyClockId())) {
            LOGGER.warn("when do dailyClock, studentDailyClock or dailyClockId is null ");
            return new BusinessResult(ResultCodeEnum.NO_QUERY_PARAM);
        }
        List<ExerciseCompletionDTO> exerciseCompletionDTOS = studentDailyClockDTO.getExerciseCompletionDTOS();
        if (CollectionUtils.isEmpty(exerciseCompletionDTOS)) {
            return result;
        }
        List<ExerciseCompletionDTO> completionDTOS = exerciseCompletionDTOS.stream().filter(Objects::nonNull)
                .filter(this::filterEmpty).collect(Collectors.toList());
        for (ExerciseCompletionDTO exerciseCompletionDTO : completionDTOS) {
            if (exerciseCompletionDTO.getEndExerciseNum() == null || exerciseCompletionDTO.getStartExerciseNum() == null
                    || exerciseCompletionDTO.getExerciseBookId() == null) {
                result.setCode(ResultCodeEnum.PARAM_ERROR.getCode());
                result.setMessage("exercise is null");
                return result;
            }
            if (exerciseCompletionDTO.getEndExerciseNum() < exerciseCompletionDTO.getStartExerciseNum()) {
                result.setCode(ResultCodeEnum.PARAM_ERROR.getCode());
                result.setMessage("start of No. can not be larger than end of No.");
                return result;
            }
            BookDO book = booksCache.get(exerciseCompletionDTO.getExerciseBookId());
            if (book == null) {
                book = bookDao.selectById(exerciseCompletionDTO.getExerciseBookId());
            }
            if (book == null) {
                result.setCode(ResultCodeEnum.DATABASE_ERROR.getCode());
                result.setMessage("the book is not found.");
                return result;
            }
            if (book.getTotalQuestion() < exerciseCompletionDTO.getEndExerciseNum()) {
                result.setCode(ResultCodeEnum.PARAM_ERROR.getCode());
                result.setMessage("end of No. can not be larger than the book's max No.");
                return result;
            }
        }
        return result;
    }

    private boolean filterEmpty(ExerciseCompletionDTO exerciseCompletionDTO) {
        if (Objects.isNull(exerciseCompletionDTO)) {
            return false;
        }
        if (exerciseCompletionDTO.getEndExerciseNum() == null || exerciseCompletionDTO.getStartExerciseNum() == null
                || exerciseCompletionDTO.getExerciseBookId() == null) {
            return false;
        }
        return true;
    }

    private StudentDailyClockDO buildStudentDailyClockDO(StudentDailyClockDTO studentDailyClockDTO) {
        StudentDailyClockDO studentDailyClockDO = new StudentDailyClockDO();
        String studentDailyClockId = studentDailyClockDTO.getStudentDailyClockId();
        studentDailyClockDO.setStudentDailyClockId(studentDailyClockId);
        studentDailyClockDO.setEnglishClockUrl(studentDailyClockDTO.getEnglishClockUrl());
        String englishStudyState =
                studentDailyClockDTO.getEnglishClockUrl() == null ? "0" : "1";
        studentDailyClockDO.setEnglishStudyState(englishStudyState);
        Date date = new Date();
        studentDailyClockDO.setPunchTime(date);
        String dataFormat = SIMPLE_DATE_FORMAT.format(date);
        studentDailyClockDO.setPunchDate(Integer.parseInt(dataFormat));
        studentDailyClockDO.setUserId(UserUtils.getUser().getUserId());
        // todo 以下几项等览山提供
//        buildFromTP(studentDailyClockDO, UserUtils.getUser().getUserAccount());

        List<ExerciseCompletionDO> exerciseCompletionDOS = Optional.ofNullable(studentDailyClockDTO.getExerciseCompletionDTOS())
                .map(exerciseCompletionDTOS ->
                        exerciseCompletionDTOS.stream().filter(Objects::nonNull).filter(this::filterEmpty)
                                .map(exerciseCompletionDTO -> {
                                    ExerciseCompletionDO exerciseCompletionDO = new ExerciseCompletionDO();
                                    exerciseCompletionDO.setStudentDailyClockId(studentDailyClockId);
                                    exerciseCompletionDO.setStartExerciseNum(exerciseCompletionDTO.getStartExerciseNum());
                                    exerciseCompletionDO.setEndExerciseNum(exerciseCompletionDTO.getEndExerciseNum());
                                    exerciseCompletionDO.setExerciseBookId(exerciseCompletionDTO.getExerciseBookId());
                                    exerciseCompletionDO.setExerciseCompletionId(StringUtil.generateUUID());
                                    return exerciseCompletionDO;
                                }).collect(Collectors.toList())).orElse(new ArrayList<>());
        studentDailyClockDO.setExerciseCompletions(exerciseCompletionDOS);
        return studentDailyClockDO;
    }

    /**
     * 获取当天的打卡信息
     *
     * @return StudentDailyClockDTO
     */
    public StudentDailyClockDTO getDailyClock() {
        StudentDailyClockDTO result = new StudentDailyClockDTO();
        TodayClockCheckReq req = new TodayClockCheckReq();
        req.setUserId(UserUtils.getUser().getUserId());
        Date startDate = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
        req.setPunchTime(startDate);
        StudentDailyClockDO studentDailyClockDO = dailyClockDao.selectByUserId(req);
        if (Objects.isNull(studentDailyClockDO)) {
            result.setStudentDailyClockId(StringUtil.generateUUID());
            result.setUserId(UserUtils.getUser().getUserId());
            return result;
        }
        result.setUserId(UserUtils.getUser().getUserId());
        result.setStudentDailyClockId(studentDailyClockDO.getStudentDailyClockId());
        result.setEnglishClockUrl(studentDailyClockDO.getEnglishClockUrl());

        List<ExerciseCompletionDO> exerciseCompletionDOS = dailyClockDao.selectExerciseCompletionById(studentDailyClockDO.getStudentDailyClockId());
        if (CollectionUtils.isEmpty(exerciseCompletionDOS)) {
            result.setExerciseCompletionDTOS(new ArrayList<>());
            return result;
        }
        List<ExerciseCompletionDTO> exerciseCompletionDTOS = exerciseCompletionDOS.stream().map(exerciseCompletionDO -> {
            ExerciseCompletionDTO exerciseCompletionDTO = new ExerciseCompletionDTO();
            exerciseCompletionDTO.setExerciseBookId(exerciseCompletionDO.getExerciseBookId());
            exerciseCompletionDTO.setStartExerciseNum(exerciseCompletionDO.getStartExerciseNum());
            exerciseCompletionDTO.setEndExerciseNum(exerciseCompletionDO.getEndExerciseNum());
            return exerciseCompletionDTO;
        }).collect(Collectors.toList());
        result.setExerciseCompletionDTOS(exerciseCompletionDTOS);
        return result;
    }

    public StudentDailyClockDTO getAuditDailyClock(String dailyClockId) {
        StudentDailyClockDTO result = new StudentDailyClockDTO();
        if (StringUtils.isEmpty(dailyClockId)) {
            LOGGER.error("when get auditDailyTask, dailyClockId is empty");
            return result;
        }
        StudentDailyClockDO studentDailyClockDO = dailyClockDao.selectAuditDailyClock(dailyClockId);
        if (Objects.isNull(studentDailyClockDO)) {
            return result;
        }
        result.setUserId(studentDailyClockDO.getUserId());
        result.setStudentDailyClockId(studentDailyClockDO.getStudentDailyClockId());
        result.setEnglishClockUrl(studentDailyClockDO.getEnglishClockUrl());
        result.setEnglishStudyState(studentDailyClockDO.getEnglishStudyState());
        result.setDailyTaskCorrectNum(studentDailyClockDO.getDailyTaskCorrectNum());
        result.setDailyTaskTotalNum(studentDailyClockDO.getDailyTaskTotalNum());
        result.setRecordedBroadcastRealNum(studentDailyClockDO.getRecordedBroadcastRealNum());
        result.setRecordedBroadcastTotalNum(studentDailyClockDO.getRecordedBroadcastTotalNum());
        result.setLiveBroadcastState(studentDailyClockDO.getLiveBroadcastState());

        List<ExerciseCompletionDO> exerciseCompletionDOS = dailyClockDao.selectExerciseCompletionById(studentDailyClockDO.getStudentDailyClockId());
        if (CollectionUtils.isEmpty(exerciseCompletionDOS)) {
            result.setExerciseCompletionDTOS(new ArrayList<>());
            return result;
        }
        List<ExerciseCompletionDTO> exerciseCompletionDTOS = exerciseCompletionDOS.stream().map(exerciseCompletionDO -> {
            ExerciseCompletionDTO exerciseCompletionDTO = new ExerciseCompletionDTO();
            exerciseCompletionDTO.setExerciseBookId(exerciseCompletionDO.getExerciseBookId());
            exerciseCompletionDTO.setStartExerciseNum(exerciseCompletionDO.getStartExerciseNum());
            exerciseCompletionDTO.setEndExerciseNum(exerciseCompletionDO.getEndExerciseNum());
            return exerciseCompletionDTO;
        }).collect(Collectors.toList());
        result.setExerciseCompletionDTOS(exerciseCompletionDTOS);
        return result;
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        List<BookDO> bookDOS = bookDao.selectAll();
        booksCache = new HashMap<>();
        if (CollectionUtils.isNotEmpty(bookDOS)) {
            bookDOS.forEach(book -> booksCache.put(book.getBookId(), book));
        }
    }
}
